#include <GL/glut.h>
#include <unistd.h>
#include <math.h>
#include <iostream>
#include <assert.h>
#include "globals_.h"
//#include "figure.h"
#include <assert.h>
#include "animation.h"
#include <algorithm>

#include <boost/random.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_01.hpp>

using namespace std;

vector<Figure *> shapes;

void functorAnimate(Figure *ptr){
	animateFigure(ptr);
}

void functorDraw(Figure *ptr){
	ptr->draw();
}

/* return if there is an intersection between two segments */
bool intersectionExists(Point a, Point b, Point c, Point d){
    float den = a.first*(d.second-c.second)+b.first*(c.second-d.second)+d.first*(b.second-a.second)+c.first*(a.second-b.second);
    if(den == 0.0){
        return false;
    }
    float s = (a.first*(d.second-c.second)+c.first*(a.second-d.second)+d.first*(c.second-a.second))/den;
    float t = -(a.first*(c.second-b.second)+b.first*(a.second-c.second)+c.first*(b.second-a.second))/den;
    if(0.0<=s && s<= 1.0 && 0.0<=t && t<=1.0) return true;
    else return false;
}

/* return the intersection point */
Point intersection(Point a, Point b, Point c, Point d){
    float den = ((a.first-b.first)*(c.second-d.second))- ((a.second-b.second)*(c.first-d.first));
    assert(den!=0.0);
    float x = ( (((a.first*b.second)-(a.second*b.first))*(c.first-d.first)) - ((a.first-b.first)*((c.first*d.second)-(c.second*d.first))) ) / den;
    float y = ( (((a.first*b.second)-(a.second*b.first))*(c.second-d.second)) - ((a.second-b.second)*((c.first*d.second)-(c.second*d.first))) ) / den;
    return Point(x,y);
}

/* Intersection between two shapes using all the points */
bool intersectionShape(Figure *a,Figure *b,Point &intersected){
	//cout<<a->vecPoints.size()<<" "<<b->vecPoints.size()<<endl;
	int size_a = a->vecPoints.size();
	int size_b = b->vecPoints.size();

	for(int i = 0 ; i < size_a; ++i){
		for(int j = 0 ; j < size_b ; ++j){
			if(intersectionExists(a->vecPoints[i%size_a],a->vecPoints[(i+1)%size_a],b->vecPoints[j%size_b],b->vecPoints[(j+1)%size_b] )){
				/*here are the intersected points --- Point structure */
				intersected = intersection(a->vecPoints[i%size_a],a->vecPoints[(i+1)%size_a],b->vecPoints[j%size_b],b->vecPoints[(j+1)%size_b]);
				return true;
			}
		}
	}
	return false;
}

/* All the shapes */
void findForIntersections(){
	assert(shapes.size()>=2);
	Point intersected;
	for(int i = 0 ; i < (int)shapes.size() ; ++i){
		if(intersectionShape(shapes[0],shapes[1],intersected)){
			cout<<"Intersection : "<<intersected.first<<","<<intersected.second<<endl;
			exit(1);
		}
	}
}

void Animation(int unused){

	findForIntersections();

	for_each(shapes.begin(),shapes.end(),functorAnimate);
//	animateFigure(shapes[1]);

	glutPostRedisplay();
	glutTimerFunc(TIME,Animation,0);
}

void Mostrar(){
	glClearColor(1,1,1,1);
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

//	gluOrtho2D(0,WIDTH,0-(round((float)radio_)/100.0),HEIGHT+(round((float)radio_)/100.0));
	gluOrtho2D(0,WIDTH,0-(round((float)radio_)),HEIGHT+(round((float)radio_)));

	for_each(shapes.begin(),shapes.end(),functorDraw);
	glFlush();

//	findForIntersections();
}


int main(int argc, char** argv){

	Figure *F1,*F2;

	F1 = new Triangle(pair<int,int>(WIDTH/2,0),radio_);
//	F2 = new Rectangle(pair<int,int>((WIDTH/2),radio_*2-0.05),radio_);
	F2 = new Rectangle(pair<int,int>((WIDTH/2),HEIGHT),radio_);

	shapes.push_back(F1);
	shapes.push_back(F2);

	glutInit(&argc, argv);

	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
	glutInitWindowPosition(100, 100);

	glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB );

	glutCreateWindow("Falling Figure !");
	glutDisplayFunc(Mostrar);
	glutTimerFunc(TIME,Animation,0);

	glutMainLoop();

	return 0;
}
